package com.vimi8.ebb.auth.configuration;

import net.sf.json.JSONObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.authentication.BearerTokenExtractor;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.util.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by xuybin on 2016/9/11.
 */
public class CookieTokenExtractor extends BearerTokenExtractor {
    private final static Log logger = LogFactory.getLog(CookieTokenExtractor.class);
    @Override
    protected String extractToken(HttpServletRequest request) {
        // first check the header...
        String cookieToken = extractHeaderToken(request);
        String token=null;
        // bearer type allows a request parameter as well
        if (cookieToken == null) {
            logger.debug("Token not found in headers. Trying request parameters.");
            cookieToken = request.getParameter(OAuth2AccessToken.ACCESS_TOKEN);
            if (cookieToken == null) {
                logger.debug("Token not found in request parameters.  Trying request cookie.");
                cookieToken=extractCookieToken(request);
                //如果token过期 token设为null
                if(!StringUtils.isEmpty(cookieToken)){
                    try {
                        Jwt jwt= JwtHelper.decode(cookieToken);
                        String claims= jwt.getClaims();
                        JSONObject jsonObject= JSONObject.fromObject(claims);
                        if(jsonObject!=null&&jsonObject.containsKey("exp")){
                            Long exp= jsonObject.optLong("exp");
                            Date expiration=new Date(exp*1000);
                            if(expiration != null && expiration.before(new Date())){
                                cookieToken=null;

                            }
                        }
                    } catch (Exception e) {
                        token=null;
                        logger.info("jwt convert exception "+e.getMessage());
                    }
                }
                token= cookieToken;
                if (token == null) {
                    logger.debug("Token not found in cookie. Not an OAuth2 request.");
                }
                else {
                    request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, OAuth2AccessToken.BEARER_TYPE);
                }
            }
        }

        return token;
    }


    protected String extractCookieToken(HttpServletRequest request) {
        Map<String,Cookie> cookieMap = ReadCookieMap(request);
        if(cookieMap.containsKey("Authorization")){
            Cookie cookie = (Cookie)cookieMap.get("Authorization");
            String value=cookie.getValue();
            if ((value.toLowerCase().startsWith(OAuth2AccessToken.BEARER_TYPE.toLowerCase()))) {
                String authHeaderValue = value.substring(OAuth2AccessToken.BEARER_TYPE.length()).trim();
                if(authHeaderValue.startsWith("%20")){
                    authHeaderValue=authHeaderValue.substring(3);
                }
                // Add this here for the auth details later. Would be better to change the signature of this method.
                request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE,
                        value.substring(0, OAuth2AccessToken.BEARER_TYPE.length()).trim());
                int commaIndex = authHeaderValue.indexOf(',');
                if (commaIndex > 0) {
                    authHeaderValue = authHeaderValue.substring(0, commaIndex);
                }
                return authHeaderValue;
            }
        }
        return null;
    }

    private static Map<String,Cookie> ReadCookieMap(HttpServletRequest request){
        Map<String,Cookie> cookieMap = new HashMap<String,Cookie>();
        Cookie[] cookies = request.getCookies();
        if(null!=cookies){
            for(Cookie cookie : cookies){
                cookieMap.put(cookie.getName(), cookie);
            }
        }
        return cookieMap;
    }
}
